/*
 * Library for accessing a Simple DNS server.
 */
#define MAX_SERVERS 10
#define MAX_NAME_LEN 63

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <unistd.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "simpledns.h"

typedef struct {
	char type;
	char host_name[MAX_NAME_LEN+1];
	addr_record record; // never used
} resolve_req;

int sock_fd[MAX_SERVERS];
struct sockaddr addresses[MAX_SERVERS];
int in_use[MAX_SERVERS];
int started = 0;

static int allocate_handle()
{
	int i;
	if(!started)
	{
		for (i = 0; i < 0; ++i) {
			in_use[i] = 0;
		}
	}
	for (i = 0; i < MAX_SERVERS; ++i) {
		if(!in_use[i])
		{
			in_use[i] = 1;
			return i;
		}
	}
	return E_NO_HANDLES_AVAILABLE;
}

int open_ns(char * ns_name, int ns_port)
{
	int sd = socket(AF_INET, SOCK_DGRAM, 0);
	struct sockaddr_in remote;
	struct hostent *hp, *gethostbyname();
	int next_handle = allocate_handle();

	remote.sin_family = AF_INET;
	if((hp = gethostbyname(ns_name)) == NULL)
	{
		fprintf(stderr, "simpledns: open_ns: gethostbyname: Could not resolve host %s\n", ns_name);
		return E_NS_NOT_FOUND;
	}
	bcopy(hp->h_addr, &remote.sin_addr.s_addr, hp->h_length);
	remote.sin_port = ns_port;
	memcpy(&addresses[next_handle], &remote, sizeof(struct sockaddr));
	sock_fd[next_handle] = sd;
	return next_handle;
}

int resolve_name(int dnsp, char * host_name, addr_record * result)
{
	resolve_req req, answer;
	unsigned int len = sizeof(struct sockaddr);
	memset(&req, 0, sizeof(resolve_req));
	req.type = 'Q';
	if(strlen(host_name) > MAX_NAME_LEN)
	{
		fprintf(stderr, "simpledns: resolve_name_by_ns: Hostname %s is too long. Limit is 63 bytes.\n", host_name);
		return E_HOSTNAME_TOO_LONG;
	}
	strcpy(req.host_name, host_name);
	sendto(sock_fd[dnsp], (char *) &req, sizeof(resolve_req), 0, &addresses[dnsp], sizeof(struct sockaddr));
	fd_set request_set;
	struct timeval timer;
	timer.tv_sec = 0;
	timer.tv_usec = 500000;

	FD_ZERO(&request_set);
	FD_SET(sock_fd[dnsp], &request_set);
	if(select(sock_fd[dnsp]+1, &request_set, NULL, NULL, &timer) > 0)
	{
		if(FD_ISSET(sock_fd[dnsp], &request_set))
		{
			recvfrom(sock_fd[dnsp], &answer, sizeof(resolve_req), 0, &addresses[dnsp], &len);
			//printf("got data!\n");
			memcpy(result, &answer.record, sizeof(addr_record));
			//printf("got %s\n", answer.host_name);
			if(answer.type == 'A')
			{
				return 0;
			}
		}
	}
	else
	{
		return E_RECV_ERROR;
	}
	return E_NO_RECORD_FOUND;
}

int register_name(int dnsp, char * host_name, addr_record * new_record)
{
	resolve_req req;
	memset(&req, 0, sizeof(resolve_req));
	req.type = 'R';
	if(strlen(host_name) > MAX_NAME_LEN)
	{
		fprintf(stderr, "simpledns: resolve_name_by_ns: Hostname %s is too long. Limit is 63 bytes.\n", host_name);
		return E_HOSTNAME_TOO_LONG;
	}
	strcpy(req.host_name, host_name);
	memcpy(&req.record, new_record, sizeof(addr_record));
	sendto(sock_fd[dnsp], (char *) &req, sizeof(resolve_req), 0, &addresses[dnsp], sizeof(struct sockaddr));
	return 0;
}

int close_dns(int dnsd)
{
	close(sock_fd[dnsd]);
	in_use[dnsd] = 0;
	return 0;
}

int main()
{
	addr_record answer;
	int nd = open_ns("localhost", 2929);
	int res = resolve_name(nd, "bogus", &answer);
	if(res == 0)
	{
		printf("found %d.%d.%d.%d\n", answer.addr[0], answer.addr[1], answer.addr[2], answer.addr[3]);
	}
	else
	{
		printf("got error: %d\n", res);
	}
	return 0;
}
